package gis

import (
	"encoding/json"
	"fmt"
	"github.com/twpayne/go-geom"
	"github.com/twpayne/go-geom/encoding/geojson"
	"github.com/twpayne/go-geom/encoding/wkt"
	"db2s/ref"
	"strconv"
	"strings"
)

func SetGSRid(g geom.T) {
	switch gg := g.(type) {
	case *geom.Polygon:
		gg.SetSRID(4326)
	}
}

type AxisOrder int

const (
	AxisOGC  AxisOrder = iota // 不翻转，保持 [lon,lat] [lon, lat]
	AxisEPSG                  // [lat, lon] for some EPS_G like 4326 (if you choose to enforce)
)

// FeatureCollection 以下是一个符合 GeoJSON 标准的简化结构体定义
type FeatureCollection struct {
	Type     string    `json:"type"` // "FeatureCollection"
	Features []Feature `json:"features"`
}

type Feature struct {
	Type       string          `json:"type"` // "Feature"
	Geometry   json.RawMessage `json:"geometry"`
	Properties map[string]any  `json:"properties,omitempty"`
	// 可选：持有 SRid 以便轴序判断（WKT/GeoJSON通常不含SRid，需要外部传入）
	SRid *int `json:"-"`
}

// Position 用于把 coordinates 解析成强类型，并按轴序落到你自定义的经纬度结构
type Position struct {
	Lon float64 `json:"lon"`
	Lat float64 `json:"lat"`
}
type LinearRing []Position         // 一个环
type PolygonPositions []LinearRing // 多个环
func intPtr(v any) *int {
	switch v.(type) {
	case int:
		r := v.(int)
		return &r
	case string:
		if s, err := strconv.Atoi(v.(string)); err != nil {
			return nil
		} else {
			return &s
		}
	default:
		return nil
	}
}

// 依据选择的轴序策略与 SRid 决定是否翻转
func shouldFlip(axis AxisOrder, SRid string) bool {
	switch axis {
	case AxisOGC:
		// OGC/GeoJSON：不翻转，保持 [lon,lat]
		return false
	case AxisEPSG:
		// 你可以更精细：只有特定 SRid 翻转
		// 常见争议：EPS_G:4326 官方轴序是 lat,lon
		if SRid == "4326" {
			return true
		}
		// 对其他 SRid，可按需扩展
		return false
	default:
		return false
	}
}

// ParsePolygonPositions 从 Feature.Geometry 中解析出 Polygon 的坐标，并按 axisOrder & SRid 处理
func (f Feature) ParsePolygonPositions(axis AxisOrder, SRid string) (PolygonPositions, error) {
	// 先把 RawMessage 解析为通用 geometry
	var g struct {
		Type        string          `json:"type"`
		Coordinates json.RawMessage `json:"coordinates"`
	}
	if err := json.Unmarshal(f.Geometry, &g); err != nil {
		return nil, err
	}
	if !strings.EqualFold(g.Type, "Polygon") {
		return nil, fmt.Errorf("geometry type is %s, not Polygon", g.Type)
	}

	// 先当作 GeoJSON 标准的 [[[x,y],...]] 解析为 float64
	var coordsFloat [][][]float64
	if err := json.Unmarshal(g.Coordinates, &coordsFloat); err != nil {
		return nil, err
	}

	// 决定是否翻转
	flip := shouldFlip(axis, SRid)

	// 映射到强类型 Position
	out := make(PolygonPositions, len(coordsFloat))
	for i, ring := range coordsFloat {
		out[i] = make(LinearRing, len(ring))
		for j, pt := range ring {
			if len(pt) < 2 {
				return nil, fmt.Errorf("invalid coordinate length at ring %d point %d", i, j)
			}
			x, y := pt[0], pt[1] // 假定源为 [x=lon, y=lat]（GeoJSON/OGC 习惯）
			if flip {
				out[i][j] = Position{Lon: y, Lat: x}
			} else {
				out[i][j] = Position{Lon: x, Lat: y}
			}
		}
	}
	return out, nil
}

// FlipGeometryIfNeeded 将 Feature 的 Geometry 由 RawMessage 翻转并回写
func (f *Feature) FlipGeometryIfNeeded(axis AxisOrder, SRid string) (err error) {
	// 1) 反序列化通用 geometry
	var g struct {
		Type        string          `json:"type"`
		Coordinates json.RawMessage `json:"coordinates"`
	}
	if err = json.Unmarshal(f.Geometry, &g); err != nil {
		return
	}
	// 2) 仅示例 Polygon，可扩展到 Point/LineString/...
	fmt.Println("---------HEIHEI：", g.Type, string(f.Geometry))
	switch strings.ToLower(g.Type) {
	case "polygon":
		var coords [][][]float64
		if err = json.Unmarshal(g.Coordinates, &coords); err != nil {
			return err
		}
		flip := shouldFlip(axis, SRid)
		if flip {
			for i := range coords {
				for j := range coords[i] {
					if len(coords[i][j]) >= 2 {
						coords[i][j][0], coords[i][j][1] = coords[i][j][1], coords[i][j][0]
					}
				}
			}
		}
		// 3) 重新编码为 Geometry JSON 并回写
		type geometryPolygon struct {
			Type        string        `json:"type"`
			Coordinates [][][]float64 `json:"coordinates"`
		}
		newGeom := geometryPolygon{Type: "Polygon", Coordinates: coords}
		b, err := json.Marshal(newGeom)
		if err != nil {
			return err
		}
		f.Geometry = b
	case "geometrycollection":
		fmt.Println("------rqqq:", string(f.Geometry))
	default:
		// 其他几何类型按需扩展
	}
	return nil
}

// ToWKT 将Feature的Geometry转换为WKT格式
func (f Feature) ToWKT(axis AxisOrder, SRid string) (string, error) {
	// 解析几何类型和坐标
	var g struct {
		Type        string          `json:"type"`
		Coordinates json.RawMessage `json:"coordinates"`
	}
	if err := json.Unmarshal(f.Geometry, &g); err != nil {
		return "", err
	}

	// 根据几何类型进行转换
	switch strings.ToLower(g.Type) {
	case "polygon":
		return f.convertPolygonToWKT(g.Coordinates, axis, SRid)
	case "linestring":
		return f.convertLineStringToWKT(g.Coordinates, axis, SRid)
	case "point":
		return f.convertPointToWKT(g.Coordinates, axis, SRid)
	default:
		return "", fmt.Errorf("unsupported geometry type: %s", g.Type)
	}
}

// 转换Polygon为WKT
func (f Feature) convertPolygonToWKT(coordsJSON json.RawMessage, axis AxisOrder, SRid string) (string, error) {
	var coords [][][]float64
	if err := json.Unmarshal(coordsJSON, &coords); err != nil {
		return "", err
	}

	flip := shouldFlip(axis, SRid)
	var wktBuilder strings.Builder
	wktBuilder.WriteString("POLYGON (")

	for i, ring := range coords {
		if i > 0 {
			wktBuilder.WriteString(", ")
		}
		wktBuilder.WriteString("(")

		for j, pt := range ring {
			if len(pt) < 2 {
				return "", fmt.Errorf("invalid coordinate length at ring %d point %d", i, j)
			}

			x, y := pt[0], pt[1]
			if flip {
				x, y = y, x
			}

			if j > 0 {
				wktBuilder.WriteString(", ")
			}
			wktBuilder.WriteString(fmt.Sprintf("%f %f", x, y))
		}
		wktBuilder.WriteString(")")
	}

	wktBuilder.WriteString(")")
	return wktBuilder.String(), nil
}

// 转换LineString为WKT
func (f Feature) convertLineStringToWKT(coordsJSON json.RawMessage, axis AxisOrder, SRid string) (string, error) {
	var coords [][]float64
	if err := json.Unmarshal(coordsJSON, &coords); err != nil {
		return "", err
	}

	flip := shouldFlip(axis, SRid)
	var wktBuilder strings.Builder
	wktBuilder.WriteString("LINESTRING (")

	for i, pt := range coords {
		if len(pt) < 2 {
			return "", fmt.Errorf("invalid coordinate length at point %d", i)
		}

		x, y := pt[0], pt[1]
		if flip {
			x, y = y, x
		}

		if i > 0 {
			wktBuilder.WriteString(", ")
		}
		wktBuilder.WriteString(fmt.Sprintf("%f %f", x, y))
	}

	wktBuilder.WriteString(")")
	return wktBuilder.String(), nil
}

// 转换Point为WKT
func (f Feature) convertPointToWKT(coordsJSON json.RawMessage, axis AxisOrder, SRid string) (string, error) {
	var coords []float64
	if err := json.Unmarshal(coordsJSON, &coords); err != nil {
		return "", err
	}

	if len(coords) < 2 {
		return "", fmt.Errorf("invalid point coordinates")
	}
	flip := shouldFlip(axis, SRid)
	x, y := coords[0], coords[1]
	if flip {
		x, y = y, x
	}

	return fmt.Sprintf("POINT (%f %f)", x, y), nil
}
func GeomMarshalJson(wktStr string) (wktJsonByte []byte, err error) {
	var g geom.T
	if g, err = wkt.Unmarshal(wktStr); err != nil {
		err = ref.ErrAddPrintf("Gis.WktToJson", err)
		return
	}
	SetGSRid(g)
	// 2) 用 geoJson.Marshal 把几何编码成 GeoJSON geometry 的 JSON 字节
	if wktJsonByte, err = geojson.Marshal(g); err != nil {
		return
	}
	return
}
func GeomWktToJson(wktStr, SRid string, axis AxisOrder) (wktJsonStr string, err error) {
	// 1) 解析 WKT 为 go-geom 几何
	var geomJSON, wktJsonByte []byte
	if geomJSON, err = GeomMarshalJson(wktStr); err != nil {
		return
	}
	// 3) 组装 Feature/FeatureCollection（自定义结构）
	feat := Feature{
		Type:       "Feature",
		Geometry:   geomJSON, // 直接塞入 RawMessage，避免二次编码
		Properties: map[string]interface{}{"name": "example polygon"},
		SRid:       intPtr(SRid),
	}
	fc := FeatureCollection{
		Type:     "FeatureCollection",
		Features: []Feature{feat},
	}
	// 构造 fc 后
	for i := range fc.Features {
		if err = fc.Features[i].FlipGeometryIfNeeded(axis, SRid); err != nil {
			return
		}
	}
	wktJsonByte, err = json.MarshalIndent(fc, "", "  ")
	wktJsonStr = string(wktJsonByte)
	return
}

func GeomJSONToWKT(geoJsonStr, SRid string, axis AxisOrder) (wktStr string, err error) {
	// 先尝试解析为基础几何类型
	var baseGeom struct {
		Type string `json:"type"`
	}
	if err = json.Unmarshal([]byte(geoJsonStr), &baseGeom); err != nil {
		return "", ref.ErrAddPrintf("Gis.GeoJSONToWKT", fmt.Errorf("json string unmarshal fail. %w", err))
	}
	// 根据不同类型处理
	switch baseGeom.Type {
	case "FeatureCollection":
		return handleFeatureCollection(geoJsonStr, axis, SRid)
	case "Feature":
		return handleFeature(geoJsonStr, axis, SRid)
	default:
		// 处理基础几何类型
		return handleBasicGeometry(geoJsonStr, axis, SRid)
	}
}

// 处理FeatureCollection类型
func handleFeatureCollection(geoJson string, axis AxisOrder, SRid string) (res string, err error) {
	var fc FeatureCollection
	if err = json.Unmarshal([]byte(geoJson), &fc); err != nil {
		return
	}
	if len(fc.Features) == 0 {
		return "", fmt.Errorf("FeatureCollection不包含任何要素")
	}
	// 转换集合中的每个要素
	var wktParts []string
	for i, feature := range fc.Features {
		var newGeomJson []byte
		if newGeomJson, err = json.Marshal(feature.Geometry); err != nil {
			return "", fmt.Errorf("解析要素 %d 的几何失败: %w", i, err)
		}
		var newWkt string
		if newWkt, err = handleBasicGeometry(string(newGeomJson), axis, SRid); err != nil {
			return "", fmt.Errorf("要素 %d value:%v 转换失败: %w", i, string(newGeomJson), err)
		}
		wktParts = append(wktParts, newWkt)
	}
	// 如果只有一个要素，直接返回其WKT
	if len(wktParts) == 1 {
		return wktParts[0], nil
	}
	// 多个要素时，返回GEOMETRYCOLLECTION
	return fmt.Sprintf("SRID=%v;GEOMETRYCOLLECTION (%s)", SRid, strings.Join(wktParts, ", ")), nil
}

// 处理Feature类型
func handleFeature(geoJSON string, axis AxisOrder, SRid string) (res string, err error) {
	var f Feature
	if err = json.Unmarshal([]byte(geoJSON), &f); err != nil {
		return
	}
	var geomJson []byte
	if geomJson, err = json.Marshal(f.Geometry); err != nil {
		return
	}
	return handleBasicGeometry(string(geomJson), axis, SRid)
}

// 处理基础几何类型
func handleBasicGeometry(geoJson string, axis AxisOrder, SRid string) (res string, err error) {
	var geoM struct {
		Type        string          `json:"type"`
		Coordinates json.RawMessage `json:"coordinates,omitempty"`
		Geometries  json.RawMessage `json:"geometries,omitempty"` // 添加geometries字段
	}
	if err = json.Unmarshal([]byte(geoJson), &geoM); err != nil {
		return "", fmt.Errorf("解析几何失败: %w", err)
	}
	switch strings.ToLower(geoM.Type) {
	case "point":
		res, err = jsonConvertPoint(geoM.Coordinates, axis, SRid)
	case "linestring":
		res, err = jsonConvertLineString(geoM.Coordinates, axis, SRid)
	case "polygon":
		res, err = jsonConvertPolygon(geoM.Coordinates, axis, SRid)
	case "multipoint":
		res, err = jsonConvertMultiPoint(geoM.Coordinates, axis, SRid)
	case "multilinestring":
		res, err = jsonConvertMultiLineString(geoM.Coordinates, axis, SRid)
	case "multipolygon":
		res, err = jsonConvertMultiPolygon(geoM.Coordinates, axis, SRid)
	case "geometrycollection":
		res, err = jsonConvertGeometryCollection(geoM.Geometries, axis, SRid) // 处理Geo
	default:
		return "", fmt.Errorf("不支持的几何类型: %s", geoM.Type)
	}
	if err != nil {
		return
	}
	return
}

// 转换点坐标
func jsonConvertPoint(coordsJSON json.RawMessage, axis AxisOrder, SRid string) (string, error) {
	var coords []float64
	if err := json.Unmarshal(coordsJSON, &coords); err != nil {
		return "", err
	}
	if len(coords) < 2 {
		return "", fmt.Errorf("无效的点坐标")
	}
	flip := shouldFlip(axis, SRid)
	x, y := coords[0], coords[1]
	if flip {
		x, y = y, x
	}
	return fmt.Sprintf("POINT (%.6f %.6f)", x, y), nil
}

// 转换线串
func jsonConvertLineString(coordsJSON json.RawMessage, axis AxisOrder, SRid string) (string, error) {
	var coords [][]float64
	if err := json.Unmarshal(coordsJSON, &coords); err != nil {
		return "", err
	}

	flip := shouldFlip(axis, SRid)
	var points []string

	for i, pt := range coords {
		if len(pt) < 2 {
			return "", fmt.Errorf("线串中点 %d 坐标无效", i)
		}

		x, y := pt[0], pt[1]
		if flip {
			x, y = y, x
		}

		points = append(points, fmt.Sprintf("%.6f %.6f", x, y))
	}
	return fmt.Sprintf("LINESTRING (%s)", strings.Join(points, ", ")), nil
}

// 转换多边形
func jsonConvertPolygon(coordsJSON json.RawMessage, axis AxisOrder, SRid string) (string, error) {
	var coords [][][]float64
	if err := json.Unmarshal(coordsJSON, &coords); err != nil {
		return "", err
	}

	flip := shouldFlip(axis, SRid)
	var rings []string

	for i, ring := range coords {
		var points []string
		for j, pt := range ring {
			if len(pt) < 2 {
				return "", fmt.Errorf("多边形环 %d 中点 %d 坐标无效", i, j)
			}
			x, y := pt[0], pt[1]
			if flip {
				x, y = y, x
			}

			points = append(points, fmt.Sprintf("%.6f %.6f", x, y))
		}
		rings = append(rings, fmt.Sprintf("(%s)", strings.Join(points, ", ")))
	}
	return fmt.Sprintf("POLYGON (%s)", strings.Join(rings, ", ")), nil
}

// 转换多点
func jsonConvertMultiPoint(coordsJSON json.RawMessage, axis AxisOrder, SRid string) (string, error) {
	var coords [][]float64
	if err := json.Unmarshal(coordsJSON, &coords); err != nil {
		return "", err
	}

	flip := shouldFlip(axis, SRid)
	var points []string

	for i, pt := range coords {
		if len(pt) < 2 {
			return "", fmt.Errorf("多点中第 %d 个点坐标无效", i)
		}

		x, y := pt[0], pt[1]
		if flip {
			x, y = y, x
		}

		points = append(points, fmt.Sprintf("(%.6f %.6f)", x, y))
	}

	return fmt.Sprintf("MULTIPOINT (%s)", strings.Join(points, ", ")), nil
}

// 转换多线串
func jsonConvertMultiLineString(coordsJSON json.RawMessage, axis AxisOrder, SRid string) (string, error) {
	var coords [][][]float64
	if err := json.Unmarshal(coordsJSON, &coords); err != nil {
		return "", err
	}

	flip := shouldFlip(axis, SRid)
	var lines []string
	for i, line := range coords {
		var points []string
		for j, pt := range line {
			if len(pt) < 2 {
				return "", fmt.Errorf("多线串 %d 中点 %d 坐标无效", i, j)
			}

			x, y := pt[0], pt[1]
			if flip {
				x, y = y, x
			}

			points = append(points, fmt.Sprintf("%.6f %.6f", x, y))
		}
		lines = append(lines, fmt.Sprintf("(%s)", strings.Join(points, ", ")))
	}

	return fmt.Sprintf("MULTILINESTRING (%s)", strings.Join(lines, ", ")), nil
}

// 转换多 polygon
func jsonConvertMultiPolygon(coordsJSON json.RawMessage, axis AxisOrder, SRid string) (string, error) {
	var coords [][][][]float64
	if err := json.Unmarshal(coordsJSON, &coords); err != nil {
		return "", err
	}

	flip := shouldFlip(axis, SRid)
	var polygons []string

	for i, polygon := range coords {
		var rings []string
		for j, ring := range polygon {
			var points []string
			for k, pt := range ring {
				if len(pt) < 2 {
					return "", fmt.Errorf("多 polygon %d 中环 %d 中点 %d 坐标无效", i, j, k)
				}

				x, y := pt[0], pt[1]
				if flip {
					x, y = y, x
				}

				points = append(points, fmt.Sprintf("%.6f %.6f", x, y))
			}
			rings = append(rings, fmt.Sprintf("(%s)", strings.Join(points, ", ")))
		}
		polygons = append(polygons, fmt.Sprintf("(%s)", strings.Join(rings, ", ")))
	}

	return fmt.Sprintf("MULTIPOLYGON (%s)", strings.Join(polygons, ", ")), nil
}

// 处理GeometryCollection类型
func jsonConvertGeometryCollection(geometriesJSON json.RawMessage, axis AxisOrder, SRid string) (res string, err error) {
	var geometries []map[string]json.RawMessage
	if err = json.Unmarshal(geometriesJSON, &geometries); err != nil {
		return
	}
	if len(geometries) == 0 {
		return
	}
	var geometryWKT []string
	for i, geo := range geometries {
		// 提取几何类型
		geoType, exists := geo["type"]
		if !exists {
			return "", fmt.Errorf("GeometryCollection中第%d个几何对象缺少type字段", i)
		}
		var typeStr string
		if err = json.Unmarshal(geoType, &typeStr); err != nil {
			return "", fmt.Errorf("解析GeometryCollection中第%d个几何对象的类型失败: %w", i, err)
		}

		// 提取坐标数据
		coords, exist := geo["coordinates"]
		if !exist {
			// 对于GeometryCollection，可能包含其他GeometryCollection
			if geometriesData, exist1 := geo["geometries"]; exist1 {
				// 递归处理嵌套的GeometryCollection
				var nestedWKT string
				if nestedWKT, err = jsonConvertGeometryCollection(geometriesData, axis, SRid); err != nil {
					return "", fmt.Errorf("处理嵌套GeometryCollection失败: %w", err)
				}
				geometryWKT = append(geometryWKT, nestedWKT)
				continue
			}
			return "", fmt.Errorf("GeometryCollection中第%d个几何对象缺少coordinates或geometries字段", i)
		}

		// 根据类型处理几何对象
		var wktStr string
		switch strings.ToLower(typeStr) {
		case "point":
			wktStr, err = jsonConvertPoint(coords, axis, SRid)
		case "linestring":
			wktStr, err = jsonConvertLineString(coords, axis, SRid)
		case "polygon":
			wktStr, err = jsonConvertPolygon(coords, axis, SRid)
		case "multipoint":
			wktStr, err = jsonConvertMultiPoint(coords, axis, SRid)
		case "multilinestring":
			wktStr, err = jsonConvertMultiLineString(coords, axis, SRid)
		case "multipolygon":
			wktStr, err = jsonConvertMultiPolygon(coords, axis, SRid)
		case "geometrycollection":
			// 处理嵌套的GeometryCollection
			wktStr, err = jsonConvertGeometryCollection(coords, axis, SRid)
		default:
			return "", fmt.Errorf("GeometryCollection中不支持的几何类型: %s", typeStr)
		}
		if err != nil {
			return "", fmt.Errorf("处理GeometryCollection中第%d个几何对象失败: %w", i, err)
		}
		// 直接使用完整的WKT表示
		geometryWKT = append(geometryWKT, wktStr)
	}
	return fmt.Sprintf("GEOMETRYCOLLECTION (%s)", strings.Join(geometryWKT, ", ")), nil
}
